package com.idroc.storage.support;

import com.idroc.storage.IoBlock;
import com.idroc.storage.IoBlockFile;

/**
 * 复合的IO块
 * 备注:将多个其他类型的IO块组成一个大的IO块
 * @author yuyoo (yuyoo4j@163.com)
 *
 */
public class ComposeFileIoBlock implements IoBlock {
	
	/**
	 * IO块文件
	 */
	private IoBlockFile file = null;
	
	/**
	 * 内部IO块的个数
	 */
	private short itemCount = 1;
	
	/**
	 * 内部IO块的大小
	 */
	private int itemSize = 0;
	
	/**
	 * 在IO块文件中的偏移
	 */
	private long offset = 0; 
	
	/**
	 * 复合IO块大小
	 */
	private int size = 0;
	
	/**
	 * 内部IO块
	 */
	private IoBlock[] blocks = null;
	
	/**
	 * IO块底层数据数组
	 */
	private byte[] backend = null;
	
	/**
	 * IO块底层数据数组中的偏移
	 */
	private int backendOffset = 0;
	
	/**
	 * 构造一个复合IO块
	 * @param start -- 第一个内部IO块
	 * @param itemCount -- 内部IO块的个数
	 * @param backend -- 底层数据数组
	 * @param backendOffset -- 底层数据开始偏移
	 */
	public ComposeFileIoBlock(IoBlock start, short itemCount, byte[] backend, int backendOffset) {
		
		initialize(start, itemCount, backend, backendOffset);
	}
	
	/**
	 * 构造一个复合IO块
	 * @param start -- 第一个内部IO块
	 * @param itemCount -- 内部IO块的个数
	 * @param lazyLoad -- 是否延迟加载
	 */
	public ComposeFileIoBlock(IoBlock start, short itemCount) {

		byte[] b = new byte[itemCount * start.size()];
		initialize(start, itemCount, b, 0);
	}
	
	/**
	 * 初始化复合IO块
	 * @param start -- 第一个内部IO块
	 * @param itemCount -- 内部IO块的个数
	 * @param backend -- 底层数据数组
	 * @param backendOffset -- 底层数据开始偏移
	 */
	protected void initialize(IoBlock start, short itemCount, byte[] backend, int backendOffset) {

		this.file = start.getIoBlockFile();
		this.offset = start.getOffset();
		this.itemCount = itemCount;
		this.itemSize = start.size();
		this.size = itemCount * itemSize;
		this.blocks = new IoBlock[itemCount];
		this.backend = backend;
		this.backendOffset = backendOffset;
		for (int i = 0; i < itemCount; i++) {
			long itemOffset = offset + i * itemSize;
			int itemBackendOffset = backendOffset + i * itemSize;
			blocks[i] = file.newIoBlock(itemOffset, backend, itemBackendOffset);
		}
	}

	/*
	 * 获取IO块所在的IO块文件
	 * @see com.idroc.storage.IoBlock#getIoBlockFile()
	 */
	public IoBlockFile getIoBlockFile() {
		
		return file;
	}

	/*
	 * 获取在IO块文件中的偏移
	 * @see com.idroc.storage.IoBlock#getOffset()
	 */
	public long getOffset() {

		return offset;
	}

	/*
	 * 是否是脏数据块
	 * @see com.idroc.storage.IoBlock#isDirty()
	 */
	public boolean isDirty() {

		for (int i = 0; i < blocks.length; i++) {
			if (blocks[i].isDirty()) {
				return true;
			}
		}
		return false;
	}

	/*
	 * 加载复合IO块的数据
	 * @see com.idroc.storage.IoBlock#load()
	 */
	public boolean load() {
		
		boolean flag = true;
		// 读取复合的所有的块
		for (int i = 0; i < itemCount; i++) {
			flag &= blocks[i].load();
		}
		return flag;
	}

	/*
	 * 读取一个字节
	 * @see com.idroc.storage.IoBlock#read(int)
	 */
	public byte read(int pos) {
		
		return backend[pos];
	}

	/*
	 * 读取一个数组
	 * @see com.idroc.storage.IoBlock#readBytes(int, int)
	 */
	public byte[] readBytes(int pos, int length) {
		
		byte[] d = new byte[length];
		System.arraycopy(backend, pos, d, 0, length);
		return d;
	}

	/*
	 * 读取一个int
	 * @see com.idroc.storage.IoBlock#readInt(int)
	 */
	public int readInt(int pos) {

		int ch0 = backend[backendOffset + pos + 0];
		int ch1 = backend[backendOffset + pos + 1];
		int ch2 = backend[backendOffset + pos + 2];
		int ch3 = backend[backendOffset + pos + 3];
		
		return (ch0 << 24) + (ch1 << 16) + (ch2 << 8) + ch3;
	}

	/*
	 * 读取一个long
	 * @see com.idroc.storage.IoBlock#readLong(int)
	 */
	public long readLong(int pos) {

		return ((long)backend[backendOffset + pos + 0] << 56)
				+ ((long)(backend[backendOffset + pos + 1] & 255) << 48)
				+ ((long)(backend[backendOffset + pos + 2] & 255) << 40)
				+ ((long)(backend[backendOffset + pos + 3] & 255) << 32)
				+ ((long)(backend[backendOffset + pos + 4] & 255) << 24)
				+ ( (backend[backendOffset + pos + 5] & 255) << 16)
				+ ( (backend[backendOffset + pos + 6] & 255) << 8)
				+ ( (backend[backendOffset + pos + 7] & 255) << 0);
	}

	/*
	 * 读取一个short
	 * @see com.idroc.storage.IoBlock#readShort(int)
	 */
	public short readShort(int pos) {

		int ch1 = backend[backendOffset + pos + 0];
	    int ch2 = backend[backendOffset + pos + 1];
		return (short)((ch1 << 8) + (ch2 << 0));
	}
 
	/*
	 * IO块大小
	 * @see com.idroc.storage.IoBlock#size()
	 */
	public int size() {

		return size;
	}

	/*
	 * 复合IO块同步数据到IO文件
	 * @see com.idroc.storage.IoBlock#sync()
	 */
	public boolean sync() {
		
		boolean flag = true;
		for (short i = 0; i < itemCount; i++) {
			if (blocks[i].isDirty()) {
				flag &= blocks[i].sync();
			}
		}
		return flag;
	}
	
	/*
	 * 写入一个字节
	 * @see com.idroc.storage.IoBlock#write(int, byte)
	 */
	public void write(int pos, byte value) {
		
		int item = pos / itemSize;
		int itemPos = pos - item * itemSize;
		blocks[item].write(itemPos, value);
	}

	/*
	 * 写入一个字节数组
	 * @see com.idroc.storage.IoBlock#write(int, byte[])
	 */
	public void write(int pos, byte[] values) {

		int item = pos / itemSize;
		int itemPos = pos - item * itemSize;
		blocks[item].write(itemPos, values);
	}

	/*
	 * 写入一个int
	 * @see com.idroc.storage.IoBlock#writeInt(int, int)
	 */
	public void writeInt(int pos, int value) {

		int item = pos / itemSize;
		int itemPos = pos - item * itemSize;
		blocks[item].writeInt(itemPos, value);		
	}

	/*
	 * 写入一个long
	 * @see com.idroc.storage.IoBlock#writeLong(int, long)
	 */
	public void writeLong(int pos, long value) {

		int item = pos / itemSize;
		int itemPos = pos - item * itemSize;
		blocks[item].writeLong(itemPos, value);		

	}

	/*
	 * 写入一个short
	 * @see com.idroc.storage.IoBlock#writeShort(int, short)
	 */
	public void writeShort(int pos, short value) {

		int item = pos / itemSize;
		int itemPos = pos - item * itemSize;
		blocks[item].writeShort(itemPos, value);		
	}

	/*
	 * 获取IO块的数据
	 * @see com.idroc.storage.IoBlock#array()
	 */
	public byte[] array() {

		return backend;
	}

	/*
	 * IO块在数组中的偏移位置
	 * @see com.idroc.storage.IoBlock#arrayOffset()
	 */
	public int arrayOffset() {

		return backendOffset;
	}

	/*
	 * 将字节数组的部分数据包装成一个IO块
	 * @see com.idroc.storage.IoBlock#wrap(byte[], int)
	 */
	public void wrap(byte[] data, int offset) {

		backend = data;
		backendOffset = offset;
		for (int i = 0; i < itemCount; i++) {
			blocks[i].wrap(data, offset + i * itemSize);
		}
	}

}
